const fs = require("fs");
const path = require("path");

// 获取指定文件夹下所有文件和文件夹
async function getFileAndFolder(pathname) {
  const files = await fs.promises.readdir(pathname);

  const result = [];
  for (let i = 0; i < files.length; i++) {
    const filename = files[i];
    const state = await fs.promises.stat(path.resolve(pathname, filename));

    result.push({
      name: filename,
      isDirectory: state.isDirectory(),
      parentPath: pathname,
    });
  }

  return result;
}

// 递归获取指定文件夹下所有文件和文件夹
async function deepGetFileAndFolder(pathname, callback = () => true) {
  const files = await getFileAndFolder(pathname);
  const newFiles = files.filter(callback);
  for (let i = 0; i < newFiles.length; i++) {
    const file = newFiles[i];
    if (file.isDirectory) {
      file.children = await deepGetFileAndFolder(
        path.resolve(file.parentPath, file.name),
        callback
      );
    }
  }

  return newFiles;
}

// 以扁平数组形式递归获取所有文件和文件夹
async function flatGetFileAndFolder(
  pathname = "",
  callback = () => true,
  result = []
) {
  const files = await fs.promises.readdir(pathname);

  for (let i = 0; i < files.length; i++) {
    const filename = files[i];
    const curFilePath = path.resolve(pathname, filename);
    const state = await fs.promises.stat(curFilePath);

    callback(filename, state) &&
      result.push({ path: curFilePath, name: filename, state });
    if (state.isDirectory()) {
      await flatGetFileAndFolder(curFilePath, callback, result);
    }
  }

  return result;
}

// 获取所有Markdown映射表
async function getMarkdownMap(pathname, obj = {}) {
  const mdList = await flatGetFileAndFolder(__dirname, (filename) =>
    filename.endsWith(".md")
  );

  for (let i = 0; i < mdList.length; i++) {
    const file = mdList[i];
    const distance = path.relative(__dirname, path.resolve(file.path));
    const level = distance.split(path.sep).length;
    const content = await fs.promises.readFile(file.path, "utf-8");
    const h1List = content.match(/# (.*)/g);
    obj[file.name] = h1List;
  }

  return obj;
}

// 根据文件树结构生成md文件结构
async function createMarkDown(data, map = {}, callback = () => true, str = "") {
  for (let i = 0; i < data?.length || 0; i++) {
    const item = data[i];
    const distance = path.relative(
      __dirname,
      path.resolve(item.parentPath, item.name)
    );
    console.log(distance);

    const level = distance.split(path.sep).length;
    if (callback(item)) {
      str += `${"".padEnd(level, "#")} [${item.name}](${distance})\n${
        map[item.name] ? map[item.name].join("、").replaceAll("#", "") : "\n"
      }\n`;
      str = await createMarkDown(item.children, map, (item) => item, str);
    }
  }

  return str;
}

(async () => {
  const exclude = [".git", "assets", ".obsidian"];
  const files = await deepGetFileAndFolder(
    __dirname,
    (file) => !exclude.includes(file.name)
  );
  const obj = await getMarkdownMap(__dirname);
  const str = await createMarkDown(
    files,
    obj,
    (file) => file.isDirectory || file.name.endsWith(".md")
  );
  await fs.promises.writeFile("./README.md", str);
})();
